package wisp.game;

//JFC
import com.golden.gamedev.object.sprite.AdvanceSprite;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.net.*;

//WISP
import wisp.dataObjects.Monster;
import wisp.dataObjects.Statistics;
import wisp.dataObjects.StatsCompPVP;
import wisp.dataObjects.WispCharacter;
import wisp.gui.SkillBar;
import wisp.gui.SkillWindow;

//import wisp.dataobjects.Statistics;

// GTGE
import com.golden.gamedev.*;
import com.golden.gamedev.object.*;
import com.golden.gamedev.engine.BaseLoader;


public abstract class PlayerSprite extends CharacterSprite {   
	
	
	private boolean hasTarget;
	private boolean attackMode;
	private CharacterSprite target;
	
	private Timer attackCooldown;
	
	//GUI skillbar; needed so that the text can be set etc
	private SkillBar skillbar;
	//key presssed; needed for the skillbar modification
	private int skillKey;
	//GUI skillwindow; used for levelling skills
	private SkillWindow skillwindow;
	
	//temporary data stats
	private double range;
	private int level;
	private WispCharacter wispcharacter;
	private Statistics statistics;
	private int currentEXP;
	private LevelInfo levelInfo;
	private double favorPoints;
	private double deedPoints;
	
	//for skill upgrading/levelling up!
	private int skillUpgradePoints;
	private int skill1level;
	private int skill2level;
	private int skill3level;
	
	//used for passive regen;
	private Timer regen;
	private int regenTime = 5000;
	
	

	public PlayerSprite(String name, MainGame game, BufferedImage[] images, double x, double y) {
        super(name, "PLAYER", game, images, x, y,true);
        
        hasTarget = false;
        attackMode = false;
        attackCooldown = new Timer(500); //0.5 second atk cooldown
        
       // initStats(150,150,60,60,500);
        initObject();
        
        levelInfo = new LevelInfo();
       /** ## 2nd change : get info from WispCharacter ## **/
      //  level = 1;
        level = getWispcharacter().getLevel();
      //  currentEXP = 0;
        currentEXP = getWispcharacter().getEPoint();
        favorPoints = getWispcharacter().getFPoint();
        deedPoints = getWispcharacter().getDPoint();
        skillUpgradePoints = getWispcharacter().getSCountLeft();
        
        initStats(getWispcharacter().getCHP(),
        		  getWispcharacter().getMHP(),
        		  getWispcharacter().getCMP(),
        		  getWispcharacter().getMMP(),
        		  500);
        /** ## 2nd change : get info from WispCharacter ## **/
        skillKey = -1;
        
        regen = new Timer(regenTime);
        regen.setActive(true);
        
        System.out.println("***" + level + "***" + this.getCurrentHP() + "***" + "\n" +		
        		    		"***" + this.getCurrentMP());
        
    }
       
    public void update(long elapsedTime) {
        super.update(elapsedTime);
      
        //For HP/MP regen
        if(regen.action(elapsedTime)){
        	this.setCurrentHP(getCurrentHP() + ((Double)(this.getStatistics().getHpGR() * 5)).intValue());
        	this.setCurrentMP(getCurrentMP() + ((Double)(this.getStatistics().getMpGR() * 5)).intValue());
        	
        }
        
        checkForSkillUse(elapsedTime);
        //if player has a target 
        if(hasTarget && target != null){
        	
        	
        	//if player is in attack mode
        	if(attackMode){
        		//if(!inRange(target, this))
        		//{	
    				setMoveLocation(target.getScreenX(), target.getScreenY());
    				move(elapsedTime);
        		//}
        		//else
        		//{	
        			commenceAttack(elapsedTime);
        			System.out.println("attack!");
        		//}
        	}
        }
        else
        	move(elapsedTime);
        /* move */
        if(!getGame().getFrame().hasClickedUI()){
            if (getGame().click()) {
            	
            	//disable attack/follow target
            	if(attackMode){
            		attackMode = false;
            		hasTarget = false;
            		target = null;
            	}
                setMoveLocation(getGame().getMouseX(), getGame().getMouseY());
            }
        }


        getBackground().setToCenter(this);
        setCopyElapsedTime(elapsedTime);
    }
    
    public void resetMode()
    {
    	hasTarget = false;
        attackMode = false;
        target = null;
    }
    
    public void commenceAttack(long elapsedTime){
    	// skills must interrupt normal attack if used
    	//so it's first
    	if(attackCooldown.action(elapsedTime)){
    		System.out.println("commence attack!");
    		performNormalAttack();
    	}
    }
    
    public boolean inRange(CharacterSprite cs, CharacterSprite self){
    	boolean value;
    	double xdistance = 0;
    	double ydistance = 0;
    	
    	if(cs.getScreenX() > self.getScreenX()){
    		xdistance = cs.getScreenX() - self.getScreenX();
    	}
    	else
    		xdistance = self.getScreenX() - cs.getScreenX();
    	
    	if(cs.getScreenY() > self.getScreenY()){
    		ydistance = cs.getScreenY() - self.getScreenY();
    	}
    	else
    		ydistance = self.getScreenY() - cs.getScreenY();
    	
    	//System.out.println(">>>> RANGE DIST : X>" + xdistance + " Y>" + ydistance + "\n\n");
    	
    	if(xdistance > this.range || ydistance > this.range){
    		value = false;
    	}
    	else
    		value = true;
    	
    	return value;
    }
    
    public abstract void checkForSkillUse(long elapsedTime);
   
    public abstract void performSkill1();
    public abstract void performSkill2();
    public abstract void performSkill3();
    
	public double performNormalAttack(){
		double damage = 0;
		boolean attackFlag = attackIsSuccessful ();
		
		//System.out.println(this.getName() + " attacks " + target.getName());
		
    	if(attackFlag == true){
    		
    		damage = this.computeDamage(attackFlag);
    		System.out.println(" perform attack! " + damage);
    		if(damage < 0)
    			damage *= -1;
    		target.hit(this,damage);
    		
    		//System.out.println("[Attack succesful] " + target.getName() + " >>> " + damage + "dmg");
    		return damage;
    	}
    	else
    	{	//System.out.println(this.getName() + " missed  " + this.getTarget().getName() + "!");
    		target.hit(this,0);
    	}
    	
    	return -1.0;
    }
    
	public double computeDamage(boolean value) {
		
		Monster monsterData = (Monster)target.getData();
		StatsCompPVP comp = new StatsCompPVP();
		return getActions().computeDamageC(wispcharacter, comp.getEQPBonus(this.getStatistics()), target.getStatistics(), monsterData, "atk", value);
	}
    
    public boolean attackIsSuccessful(){
    
    	System.out.println (">>>>>>>>>>>>>>>" + getStatistics().getARate());
    	if(getActions().getSuccessACC(getStatistics().getARate()) == true)
    	
        	return true;
        else
        	return false;
    	
    }
    
    public boolean checkTargetRange(){
    	//check the distance vector between the player and the target
    	//redo entire function to actually compute for the distance vector
    	
    	double rangeX;
    	double rangeY;
    	
    	if(target.getScreenX() >= this.getScreenX())
    		rangeX = target.getScreenX() - this.getScreenX();
    	else
    		rangeX = this.getScreenX() - target.getScreenX();
    	
    	if(target.getScreenY() >= this.getScreenY())
    		rangeY = target.getScreenY() - this.getScreenY();
    	else
    		rangeY = this.getScreenY() - target.getScreenY();
    	
    	if(rangeX <= range && rangeY <= range)
    		return true;
    	else
    		return false;
    }
  
    ///////////////////////////////////////////////////////////
    // VALUES FOR SPRITE ANIMATIONS MOVED TO INDIVIDUAL CLASSES
    ///////////////////////////////////////////////////////////
    
    
    public void attackTarget(){
    	hasTarget = true;
    	attackMode = true;
    	System.out.println(this.getName() + " is in attack mode.");
    }

	public boolean getAttackMode() {
		return attackMode;
	}

	public void setAttackMode(boolean attackMode) {
		this.attackMode = attackMode;
	}

	public boolean hasTarget() {
		return hasTarget;
	}

	public void setHasTarget(boolean hasTarget) {
		this.hasTarget = hasTarget;
	}

	public CharacterSprite getTarget() {
		return target;
	}

	public void setTarget(CharacterSprite target) {
		this.target = target;
	}
	
	public void hit(CharacterSprite cs, double damage){
		if(!attackMode)
			attackMode = true;
		
		///FOR DAMAGE DISPLAY
		this.setBeingDamaged(true);
		this.setDamagedRecieved(((Double)damage).intValue());
		
		this.getGame().getParticleGroup().add(new HitSprite(this.getGame().getImages("IMAGES/Sprites/hit.png", 3, 1), getX()+(getWidth()/2), getY()+(getHeight()/2)));
		///FLINCH
		this.setFlinch(true);
		//
		
		
		this.setCurrentHP(this.getCurrentHP() - (new Double(damage).intValue()));
		//System.out.println(this.getName() + " current HP is: " + this.getCurrentHP());
		//check if DEAD~!
		if(isDead()){

			this.getGame().getFrame().createDialog("You have died", "WiSP message");
			this.getGame().getParticleGroup().add(new AdvanceSprite(this.getGame().getImages("IMAGES/Sprites/corpse.png", 1, 1), getX(), getY()));
			
			this.setActive(false); //vaniiiiiiish
			target.resetMode();
			System.out.println(this.getName() + "is dead~");

		}
		
		
	}
	
	public WispCharacter getWispcharacter(){
		return wispcharacter;
	}
	
	public void setWispcharacter(WispCharacter wispcharacter){
		this.wispcharacter = wispcharacter;
	}
	
	@Override
	/** ### first change ### ***/
	public void initObject(){
		//wispcharacter = new WispCharacter("user", "Cantabile", 500, 500,"Templar", "Alive", "false", "none", "true", "Sallela", "Female", 1, 0, 0, 80, 80, 60, 60, 0, 10, 0, 0);
		wispcharacter = new WispCharacter();
		wispcharacter.viewChar(this.getName());
		//setStatistics(new Statistics ("Cantabile", 6, 3, 1, 4, 1, 25, 1, 1, 1, 1.5, 1, 1,1, 1, 55, 0.5, 1));
		Statistics stat = new Statistics();
		stat.viewStat(this.getName());
		setStatistics(stat);
	}
	
	@Override
	public Object getData() {
		// TODO Auto-generated method stub
		return wispcharacter;
	}
	
	public void checkIfLevelUp(int exp)
	{
		int tempEXP;
		int maxEXP = levelInfo.getExpRequired(this.level + 1);
		boolean hasLeveled = false;
		tempEXP = currentEXP + exp;
		
		if (tempEXP >= maxEXP)
		{
			animateLevelUp();
			
			//currentEXP = maxEXP - tempEXP;
			currentEXP = 0;
			
			this.level++; //need to change for DB~
			/********** temp temp *************************/
			this.getWispcharacter().setLevel(this.getLevel()); /// temporary???
			
			/// add skill points
			skillUpgradePoints++;
			
			
			System.out.println ("Character has leveled to:" +  this.level);
			this.getLevelInfo().lvlUp(this.getStatistics(), this.getWispcharacter(), this.getLevel());
			initStats(getWispcharacter().getCHP(),
	        		  getWispcharacter().getMHP(),
	        		  getWispcharacter().getCMP(),
	        		  getWispcharacter().getMMP(),
	        		  500);
			///LEVEL UP ANIMATION
			this.getGame().getMiscGroup().add(new HitSprite(this.getGame().getImages("IMAGES/Sprites/lvlup.png", 1, 4), getX(), getY()));
		}
		
		else
		{
			currentEXP = tempEXP;
			System.out.println("has gained "+ exp + " exp.");
			
		}
	}

	public int getLevel() {
		return level;
	}

	public void setLevel(int level) {
		this.level = level;
	}
	
	public LevelInfo getLevelInfo() {
		return levelInfo;
	}

	public void setLevelInfo(LevelInfo levelInfo) {
		this.levelInfo = levelInfo;
	}
	
	private void animateLevelUp() {
		// TODO Auto-generated method stub
		
	}
	
	// This is where the classes configure their skillbars
	public abstract void configSkillbar(SkillBar s);
	// Dito ung skill windows naman
	public abstract void configSkillWindow(SkillWindow s);
	public abstract void increaseSkill1();
	public abstract void increaseSkill2();
	public abstract void increaseSkill3();
    
	public SkillBar getSkillBar(){
		return skillbar;
	}
	
	public void setSkillBar(SkillBar s){
		skillbar = s;
	}
	
	public void setSkillKeyUsed(int value){
		this.skillKey = value;
	}
	
	public int getSkillKeyUsed(){
		return this.skillKey;
	}
	
	public int getCurrentEXP(){
		return currentEXP;
	}
	
	public SkillWindow getSkillWindow(){
		return skillwindow;
	}
	
	public void setSkillWindow(SkillWindow s){
		skillwindow = s;
	}
	
	public int getSkillUpgradePoints(){
		return skillUpgradePoints;
	}

	public void setSkillUpgradePoints(int s){
		skillUpgradePoints = s;
	}
	
	//used for returning the skill levels of a particular player~ needed sa skill window thingy~
	public abstract int get1stSkillLevel();
	public abstract int get2ndSkillLevel();
	public abstract int get3rdSkillLevel();

	public double getFavorPoints() {
		return favorPoints;
	}

	public void setFavorPoints(double favorPoints) {
		this.favorPoints = favorPoints;
	}
	
	public void updateDatabase()
	{
		wispcharacter.editCharInfo(this.getName(), "cLevel", null, 0.0, this.getLevel());
		wispcharacter.editCharInfo(this.getName(), "currentHP", null, 0.0, this.getCurrentHP());
		wispcharacter.editCharInfo(this.getName(), "currentMP", null, 0.0, this.getCurrentMP());
		wispcharacter.editCharInfo(this.getName(), "maxHP", null, 0.0, this.getWispcharacter().getMHP());
		wispcharacter.editCharInfo(this.getName(), "maxMP", null, 0.0, this.getWispcharacter().getMMP());
		wispcharacter.editCharInfo(this.getName(), "deedPt", null, this.getDeedPoints(), 0 );
		wispcharacter.editCharInfo(this.getName(), "sCountLeft", null, 0, this.getSkillUpgradePoints());
	}

	public double getDeedPoints() {
		return deedPoints;
	}

	public void setDeedPoints(double deedPoints) {
		this.deedPoints = deedPoints;
	}
	
}
